package com.yifan.xmlTool.util;

import com.yifan.xmlTool.annotation.IAttribute;
import com.yifan.xmlTool.annotation.IDocument;
import com.yifan.xmlTool.annotation.IElement;
import com.yifan.xmlTool.interfaces.XMLObj;
import com.yifan.xmlTool.interfaces.XMLogic;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.util.*;

/**
 * @Author YIFan
 * @Date 2021/3/2 10:27
 * @Version 1.0
 */
public class XMLUtil extends XMLObj implements XMLogic,Serializable {
    private static Logger log = LoggerFactory.getLogger(XMLUtil.class);

    public XMLUtil(Object c) {
        super(c);
        root = rootNode();
    }

    @Override
    public Element toElement() {
        eachFields();
        init();
        return root;
    }

    @Override
    public void init() {
        for (Map.Entry<String, String> i : attributes.entrySet()) {
            if (i.getValue().isEmpty()) {
                root.addAttribute(i.getKey(), "");
            } else {
                root.addAttribute(i.getKey(), i.getValue());
            }
        }
        for (Element i : elements) {
            root.add(i);
        }
    }

    @Override
    public Element rootNode() {
        IDocument idoc = model.getAnnotation(IDocument.class);
        String rootName = null;
        if (idoc != null) {
            if (idoc.name().isEmpty()) {
                rootName = model.getSimpleName();
            } else {
                rootName = idoc.name();
            }
            root = DocumentHelper.createElement(rootName);
        }
        return root;
    }

    @Override
    public void eachFields() {
        for (Field i : fields) {
            IAttribute attr = i.getAnnotation(IAttribute.class);
            IElement ele = i.getAnnotation(IElement.class);
            if (ele != null) {
                addElements(i, ele);
            }
            if (attr != null) {
                String value = attr.value();
                if (value.isEmpty()) {
                    try {
                        i.setAccessible(true);
                        Object v = i.get(obj);
                        if (v != null) {
                            value = v + "";
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                attributes.put(attr.name(), value);
            }
        }
    }

    @Override
    public void addElements(Field field, IElement ele) {
        String name = ele.name();
        if (name.isEmpty()) {
            name = field.getName();
        }
        Element element = DocumentHelper.createElement(name);

        if (field.getType() == List.class) {
            field.setAccessible(true);
            try {
                List<Element> objs = (List<Element>) field.get(obj);
                for (Element i : objs) {
                    element.add(i);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            // 子节点属性名称数组
            String[] params = ele.params();
            // 子节点属性值数组
            String[] values = ele.paramsValue();

            for (int i = 0; i < params.length; i++) {
                try {
                    String param = params[i];
                    String value = values[i];
                    // 类中的成员变量为private,故必须进行此操作
                    field.setAccessible(true);
                    Object text = field.get(obj);
                    element.addAttribute(param, value);
                    if (text != null) {
                        // 设置子节点值
                        element.setText(field.get(obj).toString());
                    }
                } catch (Exception e) {
                    log.error("ERROR:>>" + e.getMessage());
                }
            }
        }
        elements.add(element);
    }

    @Override
    public Document toDoc() {
        if(gen == null)
        {
            gen = DocumentHelper.createDocument();
            gen.add(root);
        }
        eachFields();
        init();
        return gen;
    }

    @Override
    public boolean XMLWriter(MXML xml, String filePathAndName) {
        try {
            XMLUtil xmlUtil = new XMLUtil(xml);
            OutputFormat format = OutputFormat.createPrettyPrint();
            XMLWriter writer = null;
            writer = new XMLWriter(new FileOutputStream(filePathAndName), format);
            writer.write(xmlUtil.toDoc());
            return true;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }
}
